package com.copm.demonstrationsystem.commons.util;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ResourceUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.UUID;

/**
 * @author chuyunfei
 * @date: 2018/4/15
 * @description: 关于图片的工具类
 */

public class ImageUtils {

    //日志对象
    private static Logger logger = LoggerFactory.getLogger(ImageUtils.class);

    /**
     * 1、传入要存储的文件目录位置和文件对象，返回存储后的文件名称，该文件名称是一个随机的字符串
     * @param dir：图片存储路径，是运行时环境的文件目录的本机绝对地址
     * @param file：前端以form-data编码的MultipartFile对象
     * @return ：生成的随机字符串文件名称，用于存储
     */
    public synchronized static String store(String dir,MultipartFile file){

        logger.info("存储图片在路径："+dir);

        File di = new File(dir);

        //判断文件目录是否存在，若不存在就创建该目录
        if(!di.exists()){
            di.mkdirs();
        }

        //上传文件的原始名称，用于获取文件的后缀名称
        String originalFilename = file.getOriginalFilename();

        //获取后缀名称
        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."),originalFilename.length());

        //创建新的文件名称
        String fileName = getUUIDString() + suffix;

        //创建目的文件
        File dest = new File(dir + fileName);

        //将上传的文件存储到指定的文件夹下面
        try{
            file.transferTo(dest);
        }catch(IOException e){
            logger.error(file.getOriginalFilename() + "存储失败");

            //存储失败的时候是返回null值，注意进行判断，为null是标识图片文件存储失败
            return null;
        }
        return fileName;
    }

    /**
     * 1、将传入的图片进行原样存储，指定压缩存储。
     * 2、压缩的方式是超过
     * @param dir
     * @param file
     * @return ：0 ：原图片 1 ：中等大小 2：最小
     */
    public synchronized static String[] storeAndCompressionImage(String dir,MultipartFile file){

        logger.info("存储图片在路径："+dir);

        File di = new File(dir);

        //判断文件目录是否存在，若不存在就创建该目录
        if(!di.exists()){
            di.mkdirs();
        }

        String[] results = null;
        try{
            results = new ImageCompression(file).doCompression();
        }catch(IOException e){
            e.printStackTrace();
            logger.error(file.getOriginalFilename() + "存储失败");
        }
        return results;
    }

    /**
     * 1、删除指定文件夹下面指定文件名称的文件
     * @param dir：存放图片的目录
     * @param fileName：文件的名称
     * @return ：是否删除成功，但是往往不会在意这个结果
     */
    public static Boolean delete(String dir,String fileName){

        File file = new File(dir + fileName);

        //文件不存在的情况
        return !file.exists()||file.delete();
    }

    /**
     * 1、获取一个UUID随机字符串
     * @return ：一个随机字符串
     */
    public static String getUUIDString(){
        return UUID.randomUUID().toString();
    }

    /**
     * 1、检验图片的格式是否符合要求
     * @return ：用于校验图片的格式
     */
    public static Boolean checkSuffix(String fileName){
        //获取文件名称的后缀名称
        String suffix = fileName.substring(fileName.lastIndexOf("."),fileName.length());

        //返回支持的图片文件格式
        return ".png".equalsIgnoreCase(suffix)
                || ".jpg".equalsIgnoreCase(suffix)
                || ".jpeg".equalsIgnoreCase(suffix)
                || ".gif".equalsIgnoreCase(suffix);
    }

    /**
     * 1、获取存储图片文件的目录
     * @return ：获取项目运行时的
     */
    public static String getImageDir() throws FileNotFoundException{
        //获取项目根路径
        File file = new File(ResourceUtils.getURL("classpath:").getPath());
        //获取图片的路径
        return file.getAbsolutePath() + File.separator + "static" + File.separator + "image" + File.separator;
    }

    /**
     * 用于图片的处理，压缩等等
     */
    private static class ImageCompression{
        //大的图片不超过700KB
        public static final int MIDDLE_IMAGE_SIZE = 700*1024;
        //小的图片不超过200KB
        public static final int MIN_IMAGE_SIZE = 200*1024;
        //1M的大小
        private static int MB = 1024*1024;
        //文件流
        private MultipartFile multipartFile;
        //用于存储处理后的结果
        private String[] results = null;
        //图片文件
        private Image originImage;
        //源宽度
        private Integer width;
        //源高度
        private Integer height;
        //源文件大小
        private Long originContentLength;
        //源文件名称
        private String originalFilename;
        //文件的后缀名称
        private String suffix;
        //现在的文件大小
        private Integer currentContentLength;
        /**
         * 构造函数
         * @throws IOException
         */
        ImageCompression(MultipartFile multipartFile) throws IOException{
            this.multipartFile = multipartFile;
            this.originContentLength = multipartFile.getSize();
            this.currentContentLength = originContentLength.intValue();
            this.originImage = ImageIO.read(multipartFile.getInputStream());
            this.width = originImage.getWidth(null);
            this.height = originImage.getHeight(null);
            this.originalFilename = multipartFile.getOriginalFilename();
            this.suffix = originalFilename.substring(originalFilename.lastIndexOf("."),originalFilename.length());
        }

        /**
         * 工作函数，用于实现图片压缩
         */
        String[] doCompression() throws IOException{
            //针对不同的图片大小进行图片的压缩
            //1.原图片小于200KB
            if(originContentLength <= MIN_IMAGE_SIZE){
                results = new String[3];
                logger.info("存储了一个小于200kb的图片");
                String originPath = ImageUtils.store(ImageUtils.getImageDir(),multipartFile);
                results[0]=results[1]=originPath;
                results[2]=resizeFix((int)(((double)width)/1.1),(int)(((double)height)/1.1));
            }
            //2.源文件在200KB-1MB之间时，进行一次压缩：缩小5倍左右
            else if(originContentLength >MIN_IMAGE_SIZE && originContentLength <= MB){
                results = new String[3];
                logger.info("存储了一个超过200KB的图片");
                String originPath = ImageUtils.store(ImageUtils.getImageDir(),multipartFile);
                results[0]=originPath;
                //缩小5倍
                results[1]= resizeFix((int)(((double)width)/1.1),(int)(((double)height)/1.1));
                //缩小10倍
                results[2] = resizeFix((int)(((double)width)/2),(int)(((double)height)/2));
            }
            //3.源文件超过1MB，直接缩小10倍
            else{
                results = new String[3];
                logger.info("存储了一个超过1MB的图片");
                String originPath = ImageUtils.store(ImageUtils.getImageDir(),multipartFile);

                results[0]=originPath;
                //缩小10倍
                results[1]= resizeFix(width/2,height/2);
                //缩小
                results[2] = resizeFix((int)(((double)width)/2.2),(int)(((double)height)/2.2));
            }
            return results;
        }

        /**
         * 按照宽度还是高度进行压缩
         * @param w int 最大宽度
         * @param h int 最大高度
         */
        private String resizeFix(int w, int h) throws IOException {
            if (width / height > w / h) {
                return resizeByWidth(w);
            } else {
                return resizeByHeight(h);
            }
        }
        /**
         * 以宽度为基准，等比例放缩图片
         * @param w int 新宽度
         */
        private String resizeByWidth(int w) throws IOException {
            int h = (int) (height * w / width);
            return resize(w, h);
        }
        /**
         * 以高度为基准，等比例缩放图片
         * @param h int 新高度
         */
        private String resizeByHeight(int h) throws IOException {
            int w = (int) (width * h / height);
            return resize(w, h);
        }
        /**
         * 强制压缩/放大图片到固定的大小
         * @param w int 新宽度
         * @param h int 新高度
         */
        private String resize(int w, int h) throws IOException {

            int type = BufferedImage.TYPE_INT_RGB;
            if(suffix.equalsIgnoreCase(".png")){
                type = BufferedImage.TYPE_INT_ARGB;
            }
            BufferedImage image = new BufferedImage(w, h,type);
            image.getGraphics().drawImage(originImage, 0, 0, w, h, null);
            String fileName = getUUIDString()+suffix;
            String filePath = getImageDir()+ fileName;
            File destFile = new File(filePath);

            if(type == BufferedImage.TYPE_INT_ARGB){
                ImageIO.write(image,"png",destFile);
            }else {
                FileOutputStream out = new FileOutputStream(destFile); // 输出到文件流
                // 可以正常实现bmp、png、gif转jpg
                JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
                encoder.encode(image); // JPEG编码
                out.close();
            }
            return fileName;
        }
    }
}
